package com.ydj.framework.config;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
import com.ydj.AppEnvironment;
import com.ydj.framework.exception.*;
import com.ydj.framework.protocol.JsonResponseCode;
import com.ydj.framework.protocol.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;

/**
 * @author Kwong
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
	/**
	 * 实体接收参数错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
//    @ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public JsonResult<?> methodArgumentNotValidExceptionHandle(MethodArgumentNotValidException e) {
		List<ObjectError> errors = e.getBindingResult().getAllErrors();
		if (!errors.isEmpty()) {
			return JsonResult.error(errors.get(0).getDefaultMessage());
		}
		return JsonResult.error("bad request");
	}

	/**
	 * 传入的 URL 在 Controller 找不到
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ResponseStatus(HttpStatus.NOT_FOUND)
	@ExceptionHandler(NoHandlerFoundException.class)
	public JsonResult<?> urlErrorExceptionHandle(NoHandlerFoundException e) {
		log.warn("传入的 URL 在 Controller 找不到：{}", e.getRequestURL());
		return JsonResult.error("传入的 URL 在 Controller 找不到：" + e.getRequestURL());
	}

	/**
	 * 全局错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(Exception.class)
	public JsonResult<?> exceptionHandle(Exception e) {
		log.error("全局错误：", e);
		return JsonResult.error("网络异常，请稍后再试");
	}

	/**
	 * Content Type 不支持错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
	public JsonResult<?> httpMediaTypeNotSupportedExceptionHandle(HttpMediaTypeNotSupportedException e) {
		return JsonResult.error("不支持该content type");
	}

	/**
	 * JSON 解析错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public JsonResult<?> requestParameterExceptionHandle(HttpMessageNotReadableException e) {
		Throwable cause = e.getCause();
		if (cause instanceof ValueInstantiationException && cause.getCause() instanceof RequestParameterException || cause instanceof JsonMappingException) {
			log.error("解析 JSON 错误。", e.getCause().getCause());
			return JsonResult.error(JsonResponseCode.ParameterError, e.getCause().getCause().getMessage());
		}
		log.error("解析 JSON 错误", e);
		return JsonResult.error(e.getMessage());
	}

	/**
	 * CommonException 错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(CommonException.class)
	public JsonResult<?> commonExceptionHandler(CommonException e) {
		return JsonResult.error(e.getMessage());
	}

	/**
	 * ErrorCodeException 错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(RequestFrequentlyException.class)
	public JsonResult<?> errorCodeExceptionHandler(RequestFrequentlyException e) {
		return JsonResult.error(JsonResponseCode.RequestFrequently);
	}

	/**
	 * NotRollBackAndShowException
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(NotRollBackAndShowException.class)
	public JsonResult<?> notRollBackAndShowExceptionHandler(NotRollBackAndShowException e) {
		return JsonResult.error(e.getMessage());
	}

	/**
	 * 登录验证身份错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(VerifyTokenException.class)
	public JsonResult<?> verifyTokenExceptionHandler(VerifyTokenException e) {
		return JsonResult.error(JsonResponseCode.TokenValidationError);
	}

	/**
	 * 触发限流错误
	 *
	 * @param e 异常
	 * @return  返回值
	 */
	@ResponseBody
	@ExceptionHandler(RateLimiterException.class)
	public JsonResult<?> rateLimiterExceptionHandler(RateLimiterException e) {
		return JsonResult.error("系统繁忙，请稍后再试");
	}

	/**
	 * 用错GET的方法
	 */
	@ResponseBody
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public JsonResult<?> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
		return JsonResult.error("不支持该方式调用");
	}

	/**
	 * 用GET表单请求，缺少参数
	 */
	@ResponseBody
	@ExceptionHandler(MissingServletRequestParameterException.class)
	public JsonResult<?> missingServletRequestParameterException(MissingServletRequestParameterException e) {
		return JsonResult.error("缺少了参数. 具体情况是" + e.getMessage());
	}

	@ResponseBody
	@ExceptionHandler(DistributedLockException.class)
	public JsonResult<?> distributedLockException(DistributedLockException e) {
		String msg = e.getMessage();
		if (StringUtils.isBlank(msg)) {
			msg = "正在处理中，请稍后...";
		}
		return JsonResult.error(msg);
	}

}